10.5 性能
反射在带来“方便”的同时,也造成了很大的困扰。很多人对反射避之不及,因为它会造成很大的性能损失。但损失到底有多大?我们简单测试一下。
先看看直接赋值和反射赋值的性能差异。
type Data struct{ X int }
var d=new(Data)
func set(x int) { d.X=x }
func rset(x int) { v:=reflect.ValueOf(d).Elem() f:=v.FieldByName(“X”) f.Set(reflect.ValueOf(x)) }
func BenchmarkSet(b*testing.B) { for i:=0;i<b.N;i++ { set(100) } }
func BenchmarkRset(b*testing.B) { for i:=0;i<b.N;i++ { rset(100) } }
输出:
$go test-run None-bench. -benchmem
BenchmarkSet-4 2000000000 0.52 ns/op 0 B/op 0 allocs/op BenchmarkRset-4 10000000 154 ns/op 16 B/op 2 allocs/op
这差距有些吓人。改进一下,将反射数据“缓存”起来。
var v=reflect.ValueOf(d).Elem() var f=v.FieldByName(“X”)
func rset(x int) { f.Set(reflect.ValueOf(x)) }
输出:
$go test-run None-bench. -benchmem
BenchmarkSet-4 2000000000 0.54 ns/op 0 B/op 0 allocs/op BenchmarkRset-4 20000000 55.1 ns/op 8 B/op 1 allocs/op
改进后性能有所提升,但差距还是非常大。接下来,试试方法直接调用,和反射调用对比一下性能。
type Data struct{ X int }
func(x*Data)Inc() { x.X++ }
var d=new(Data) var v=reflect.ValueOf(d) var m=v.MethodByName(“Inc”)
func call() { d.Inc() }
func rcall() { m.Call(nil) }
输出:
$go test-run None-bench. -benchmem
BenchmarkCall-4 1000000000 2.23 ns/op 0 B/op 0 allocs/op BenchmarkRcall-4 10000000 167 ns/op 0 B/op 0 allocs/op
如对性能要求较高,那么须谨慎使用反射。